package com.norns.torque

import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.norns.torque.bluetooth.ChatServer
import com.norns.torque.entrty.DeviceScanViewState
import com.norns.torque.entrty.WifiDevice
import com.norns.torque.listener.BluetoothStateListener
import com.norns.torque.listener.ConnectedListener
import com.norns.torque.utils.AppConstant
import com.norns.torque.utils.AppContext
import timber.log.Timber

// 30 second scan period
private const val SCAN_PERIOD = 4000L

class DeviceScanViewModel : ViewModel() {
    private val scanResults = mutableMapOf<String, BluetoothDevice>()
    // LiveData for sending the view state to the DeviceScanFragment
    private val _viewState = MutableLiveData<DeviceScanViewState>()
    val viewState = _viewState as LiveData<DeviceScanViewState>
    val deviceList: ArrayList<WifiDevice> = ArrayList()
    // BluetoothAdapter should never be null since BLE is required per
    // the <uses-feature> tag in the AndroidManifest.xml
    // This property will be null if bluetooth is not enabled
    private var scanner: BluetoothLeScanner? = null
    private var scanCallback: DeviceScanCallback? = null
    private val scanFilters: List<ScanFilter>
    private val scanSettings: ScanSettings

    private val _connectionState = MutableLiveData<Int>()
    val connectionState = _connectionState as LiveData<Int>

    //蓝牙开关状态
    private val _bluetoothState = MutableLiveData<Int>()
    val bluetoothState = _bluetoothState as LiveData<Int>

    private val connectedListener:ConnectedListener
    private val bluetoothStateListener:BluetoothStateListener
    init {
        // Setup scan filters and settings
        scanFilters = buildScanFilters()
        scanSettings = buildScanSettings()
        // Start a scan for BLE devices
        connectedListener= object: ConnectedListener {
            override fun onConnected(connectedState: Int) {
                if (_connectionState.value!=connectedState){
                    _connectionState.postValue(connectedState)
                    if (connectedState == AppConstant.connectionSuccess) {//连接成功
                        ChatServer.initHandler()//获取rssi
                    }
                }
            }
        }
        bluetoothStateListener = object : BluetoothStateListener {
            override fun onState(bluetoothState: Int) {
                _bluetoothState.value=bluetoothState
            }
        }
        ChatServer.addConnectionListener(connectedListener)
        ChatServer.addBluetoothStateListener(bluetoothStateListener)
    }

    override fun onCleared() {
        stopScanning()
        ChatServer.removeConnectionListener(connectedListener)
        ChatServer.removeBluetoothStateListener(bluetoothStateListener)
        scanResults.clear()
        deviceList.clear()
        super.onCleared()
    }

    @SuppressLint("MissingPermission")
    fun startScan() {
        deviceList.clear()
        if (scanCallback == null) {
            val bluetoothManager = AppContext.context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
            val bluetoothAdapter = bluetoothManager.adapter
            scanner = bluetoothAdapter.bluetoothLeScanner
            Timber.d( "Start Scanning")
            // Stop scanning after the scan period
            Handler(Looper.myLooper()!!).postDelayed({ stopScanning() }, SCAN_PERIOD)
            // Kick off a new scan
            scanCallback = DeviceScanCallback()
            scanner?.startScan(scanFilters, scanSettings, scanCallback)
        } else {
            Timber.d("Already scanning")
        }
    }

    @SuppressLint("MissingPermission")
    fun stopScanning() {
        Timber.d( "Stopping Scanning")
        _viewState.value = DeviceScanViewState.ScanCompletion()
        if (null!=scanCallback){
            val bluetoothManager = AppContext.context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
            val bluetoothAdapter = bluetoothManager.adapter
            if (null == bluetoothAdapter || !bluetoothAdapter.isEnabled) {
                if (deviceList.isEmpty()){
                    // return the current results
                    val head=WifiDevice("未开启蓝牙","",0)
                    head.type="foot"
                    deviceList.add(head)
                }
                return
            }
            scanner?.stopScan(scanCallback)
            scanCallback = null
            if (deviceList.isEmpty()){
                // return the current results
                val head=WifiDevice("没有扫描到设备","",0)
                head.type="foot"
                deviceList.add(head)
            }
        }
    }

    /**
     * Return a List of [ScanFilter] objects to filter by Service UUID.
     */
    private fun buildScanFilters(): List<ScanFilter> {
        val builder = ScanFilter.Builder()
        // Comment out the below line to see all BLE devices around you
        //builder.setServiceUuid(ParcelUuid(SERVICE_UUID))
        val filter = builder.build()
        return listOf(filter)
    }

    /**
     * Return a [ScanSettings] object set to use low power (to preserve battery life).
     */
    private fun buildScanSettings(): ScanSettings {
        return ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .build()
    }

    /**
     * Custom ScanCallback object - adds found devices to list on success, displays error on failure.
     */
    private inner class DeviceScanCallback : ScanCallback() {
        override fun onBatchScanResults(results: List<ScanResult>) {
            super.onBatchScanResults(results)
            for (item in results) {
                item.device?.let { device ->
                    scanResults[device.address]=device
                    findDevice(item)
                }
            }
            _viewState.value = DeviceScanViewState.ScanResults(deviceList)
        }

        override fun onScanResult(
            callbackType: Int,
            result: ScanResult
        ) {
            super.onScanResult(callbackType, result)
            result.device?.let { device ->
                scanResults[device.address]=device
                findDevice(result)
            }
            _viewState.value = DeviceScanViewState.ScanResults(deviceList)
        }

        override fun onScanFailed(errorCode: Int) {
            super.onScanFailed(errorCode)
            // Send error state to the fragment to display
            val errorMessage = "Scan failed with error: $errorCode"
            val head=WifiDevice("扫描失败","",0)
            head.type="foot"
            deviceList.add(head)
            _viewState.value = DeviceScanViewState.ScanResults(deviceList)
            _viewState.value = DeviceScanViewState.Error(errorMessage)
        }
    }
    @SuppressLint("MissingPermission")
    private fun findDevice(result:ScanResult){
        val device = result.device
        val deviceName = device.name ?: "Unknown"
        val deviceAddress = device.address
        val rssi = result.rssi

        var contentState = if (device.bondState == BluetoothDevice.BOND_NONE) {
            "未配对"
        } else if (device.bondState != BluetoothDevice.BOND_BONDED) {
            "已配对"
        } else {
            "配对中"
        }
        if (result.isConnectable){
            contentState +=" 可连接"
        }else{
            contentState +=" 不可连接"
        }
        //val power = (abs(rssi) - 59) / 25.0
        //val distance = Formatter().format("%.2f", pow(10.0, power)).toString()+"m"

        val result = deviceList.find { dev ->
            dev.address == deviceAddress
        }
        if (null== result) {
            //未配对
            val wifiDevice= WifiDevice(deviceName, deviceAddress,0)
            wifiDevice.distance="${rssi}dbm"
            wifiDevice.contentState=contentState
            deviceList.add(wifiDevice)
        }else{
            result.contentState=contentState
            result.distance="${rssi}dBm"
        }
        //Timber.d("发现BLE设备: 名称 - $deviceName, 地址 - $deviceAddress, 信号强度 - $rssi")
    }


    fun getBluetoothDevice(mac: String):BluetoothDevice? {
       return scanResults[mac]
    }

    fun setCurrentChatConnection(device: BluetoothDevice) {
        ChatServer.setCurrentChatConnection(device)
    }

}